/*
 *             Copyright (C) 2023 Steve Jrong
 * 
 * 	   GitHub Homepage: https://www.github.com/SteveJrong
 *      Gitee Homepage: https://gitee.com/stevejrong1024
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.stevejrong.groovy.shell

import java.nio.file.*
import java.util.stream.Stream

/**
 * Delete dir/file groovy script.
 *
 * example execute command:
 *      groovy delete_file.groovy ---file1.txt ---output
 *
 * Create by: SteveJrong
 */

static void main(String[] args) {
    DeleteResourcesAction.doAction(args)
}

final class DeleteResourcesAction {
    private enum ResourceType {
        DIR('目录'), FILE('文件')
        private String val

        ResourceType(String val) {
            this.val = val
        }

        String getVal() {
            return val
        }
    }

    private static final class ResultDTO {
        private String trulyPath
        private boolean deleteResult
        private ResourceType resourceType

        ResultDTO(String trulyPath, boolean deleteResult, ResourceType resourceType) {
            this.trulyPath = trulyPath
            this.deleteResult = deleteResult
            this.resourceType = resourceType
        }
    }

    static void doAction(String[] args) {
        def deleteResultList = new ArrayList<ResultDTO>(args.length)
        def paramSymbol = '---'
        def paramSymbolLength = paramSymbol.length()

        Stream.of(args).forEach { stringPath ->
            def trimStringPath = stringPath.trim()
            def trulyPath = trimStringPath.substring(paramSymbolLength, trimStringPath.length())

            if (FileUtils.hasDir(trulyPath)) {
                deleteResultList.add(new ResultDTO(trulyPath, FileUtils.deleteDir(trulyPath), ResourceType.DIR))
            } else {
                deleteResultList.add(new ResultDTO(trulyPath, FileUtils.deleteFile(trulyPath), ResourceType.FILE))
            }
        }

        deleteResultList.each { result ->
            println(String.format('【Delete a %s】 path -> %s, result -> %s.',
                    result.resourceType.val, result.trulyPath, result.deleteResult))
        }
    }
}

/**
 * 文件工具类
 */
final class FileUtils {
    /**
     * 根据字符路径获取java.nio.Path对象
     * @param sourcePath
     * @return
     */
    private static Path getPathByStringPath(String sourcePath) {
        return Paths.get(sourcePath)
    }

    /**
     * 判断指定的目录是否存在
     * @param dir
     * @return
     */
    static boolean dirExists(String dir) {
        return Files.exists(getPathByStringPath(dir), LinkOption.NOFOLLOW_LINKS)
    }

    /**
     * 判断指定的路径是否为文件
     * @param sourcePath
     * @return true - 为目录；false - 为文件
     */
    static boolean hasDir(String sourcePath) {
        return Files.isDirectory(getPathByStringPath(sourcePath))
    }

    /**
     * 删除单个文件
     * @param sourcePath
     * @return
     */
    static boolean deleteFile(String sourcePath) {
        Files.deleteIfExists(getPathByStringPath(sourcePath))
    }

    /**
     * 删除单个文件
     * @param pathObject
     * @return
     */
    static boolean deleteFile(Path pathObject) {
        try {
            Files.deleteIfExists(pathObject)

        } catch (ignored) {
            return false
        }
        return true
    }

    /**
     * 删除目录
     * @param sourcePath
     * @return
     */
    static boolean deleteDir(String sourcePath) {
        def result = true

        // 得到当前目录的目录树
        def dirLists = iteratorToSubDir(sourcePath, new LinkedList<String>())
        Collections.reverse(dirLists)
        dirLists.forEach { dir ->
            List<String> filesPathList = getAllFilesPathListInDirectory(dir)

            if (filesPathList.size() == 0)
                result = deleteEmptyDirectory(dir) // 目录下无文件，直接删除目录
            else // 否则迭代删除当前目录下的所有文件
                filesPathList.forEach { filePath ->
                    if (!deleteFile(filePath))
                        result = false
                }
        }

        return result
    }

    /**
     * 返回一个目录的目录树集合
     * 适用于目录中有若干层子目录的情况
     *
     * @param dir
     * @param dirList
     * @return
     */
    private static LinkedList<String> iteratorToSubDir(String dir, LinkedList<String> dirList) {
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(getPathByStringPath(dir))) {
            for (Path p : stream) {
                def pp = p.toAbsolutePath().toString()
                if (hasDirectoryPath(pp))
                    iteratorToSubDir(pp, dirList)
                dirList.push(dir)
                break
            }
        }

        return dirList
    }

    /**
     * 查找目录下的所有文件，并返回其文件路径的集合
     *
     * @param dir
     * @return
     */
    private static List<String> getAllFilesPathListInDirectory(String dir) {
        def filesPathList = new ArrayList()
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(getPathByStringPath(dir))) {
            stream.forEach { path ->
                if (!Files.isDirectory(path))
                    filesPathList.add(path.toAbsolutePath().toString())
            }
        }

        return filesPathList
    }

    /**
     * 删除空目录
     *
     * @param dir
     * @return
     */
    private static boolean deleteEmptyDirectory(String dir) {
        return Paths.get(dir).deleteDir()
    }

    /**
     * 判断给定的路径是目录还是文件
     *
     * @param filePath
     * @return
     */
    static boolean hasDirectoryPath(String filePath) {
        return filePath.lastIndexOf('.') == -1 // true is directory path, false is file path
    }
}